home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockPhotoUploadService.js < prev    next >
Text File  |  2007-10-18  |  37KB  |  1,044 lines

  1. // BEGIN FLOCK GPL
  2. // 
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. // 
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. // 
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. // 
  15. // END FLOCK GPL
  16.  
  17. const Cc = Components.classes;
  18. const Ci = Components.interfaces;
  19. const Cr = Components.results;
  20.  
  21. Components.utils.import("resource:///modules/FlockCryptoHash.jsm");
  22.  
  23. const FLOCK_PHOTO_UPLOAD_CID        = Components.ID('{9d499deb-fd01-43d5-9eda-91783a37f3bc}');
  24. const FLOCK_PHOTO_UPLOAD_FNAME      = "flock_photo_uploads.rdf";
  25.  
  26. const FLOCK_PHOTO_UPLOADS_CONTRACTID = '@mozilla.org/rdf/datasource;1?name=flock-photo-uploads';
  27. const LOCAL_FILE_CONTRACTID         = '@mozilla.org/file/local;1';
  28. const PREFERENCES_CONTRACTID        = '@mozilla.org/preferences-service;1';
  29. const IO_SERVICE_CONTRACTID         = '@mozilla.org/network/io-service;1';
  30. const FLOCK_ERROR_CONTRACTID        = "@flock.com/error;1";
  31.  
  32. const FLOCK_NS                      = 'http://flock.com/rdf#';
  33. const FLOCK_RDF_UPLOAD_ROOT         = 'urn:flock:photo:upload';
  34.  
  35. function flock_getImageUtils() {
  36.   return Cc['@flock.com/imagescaler;1'].createInstance(Ci.flockIImageScaler);
  37. }
  38.  
  39. function flockPhotoUploadService() {
  40.   var profd = Cc['@mozilla.org/file/directory_service;1'].getService(Ci.nsIProperties).get('ProfD', Ci.nsIFile);
  41.   var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsILocalFile);
  42.   try {
  43.     file.initWithPath(profd.path);
  44.   }
  45.   catch(e) {
  46.     var tmpd = Components.classes['@mozilla.org/file/directory_service;1'].
  47.       getService(Ci.nsIProperties).get('TmpD', Ci.nsIFile);
  48.     file.initWithPath(tmpd.path);
  49.   }
  50.  
  51.   file.append(FLOCK_PHOTO_UPLOAD_FNAME);
  52.   // if(!file.exists()) file.createUnique(0,0600);
  53.  
  54.   var ios = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
  55.   var fileHandler = ios.getProtocolHandler('file').QueryInterface(Ci.nsIFileProtocolHandler);
  56.   var spec = fileHandler.getURLSpecFromFile(file);
  57.  
  58.   this.listeners = Array();
  59.   this.ds = new RDFDataSource(spec);
  60.   this.dataSource = this.ds.getRawDataSource().QueryInterface (Ci.nsIRDFRemoteDataSource);
  61.   this.uploadRoot = this.ds.getNode(FLOCK_RDF_UPLOAD_ROOT);
  62.   this.uploadRoot.makeSeq();
  63.  
  64.   this.Flush();
  65.  
  66.   this.obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
  67.   this.obs.addObserver(this, 'flock-data-ready', false);
  68.  
  69.   var inst = this;
  70.   this.mTimerFunc = {
  71.     notify: function(aTimer) {
  72.       inst.Flush();
  73.     }
  74.   }
  75.   this.mTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  76.   this.running = false;
  77.   this._isImporting = false;
  78.   this.mImportQueue = Array();
  79.   this.mAsyncCopier = Cc["@mozilla.org/network/async-stream-copier;1"].createInstance(Ci.nsIAsyncStreamCopier);
  80. }
  81.  
  82.  
  83. flockPhotoUploadService.prototype.init = function PUS_init () {
  84.   // Logger
  85.   this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
  86.   this.logger.init("photoUploadService");
  87.  
  88.   // Prepare the data 
  89.   this._coop = Cc["@flock.com/singleton;1"]
  90.                .getService(Ci.flockISingleton)
  91.                .getSingleton("chrome://flock/content/common/load-faves-coop.js")
  92.                .wrappedJSObject;
  93. }
  94.  
  95.  
  96. flockPhotoUploadService.prototype.doSave = function(aListener) {
  97.   this.mTimer.cancel();
  98.   this.mTimer.initWithCallback(this.mTimerFunc,2*1000,0);//re-check token
  99. }
  100.  
  101.  
  102. flockPhotoUploadService.prototype.addListener = function(aListener) {
  103.   this.listeners.push(aListener);
  104.   debug("adding photo upload listener " + this.listeners.length + "\n");
  105. }
  106.  
  107.  
  108. flockPhotoUploadService.prototype.removeListener = function(aListener) {
  109.   for(var i=0;i<this.listeners.length;++i) {
  110.     if(aListener==this.listeners[i]) {
  111.       this.listeners.splice(i,1);
  112.       break;
  113.     }
  114.   }
  115. }
  116.  
  117.  
  118. flockPhotoUploadService.prototype.hasOnePhotoAccount = function PUS_hasOnePhotoAccount () {
  119.   var haveAccount = false;
  120.   // Iterate through all accounts, looking for photo upload accounts.
  121.   // Separate them according to auth state
  122.   var accountsEnum = this._coop.accounts_root.children.enumerate();
  123.   while (accountsEnum.hasMoreElements()) {
  124.     var acctCoopObj = accountsEnum.getNext();
  125.     if (!acctCoopObj) continue; // getNext() can return NULL when hasMoreElements() is TRUE.
  126.     try {
  127.       var svc = Cc[acctCoopObj.serviceId].getService(Ci.flockIWebService);
  128.       svc.QueryInterface(Components.interfaces.flockIMediaWebService);
  129.       var acct = svc.getAccount(acctCoopObj.id());
  130.       acct.QueryInterface(Components.interfaces.flockIMediaUploadAccount);
  131.       haveAccount = true;
  132.     } catch (ex) {
  133.       // This account is not a flockIMediaUploadAccount
  134.     }
  135.   }
  136.   
  137.   return haveAccount; 
  138. }
  139.  
  140.  
  141. flockPhotoUploadService.prototype.promptForAccount = function PUS_promptForAccount () {
  142.   var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  143.   var win = wm.getMostRecentWindow('navigator:browser');
  144.  
  145.   var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
  146.             .getService(Ci.nsIStringBundleService);
  147.   var sb = sbs
  148.            .createBundle("chrome://flock/locale/photo/photo.properties");
  149.  
  150.   var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  151.                   .getService(Components.interfaces.nsIPromptService);
  152.   if (promptService.confirm(win, sb.GetStringFromName("flock.photo.alert.title"), sb.GetStringFromName("flock.photo.alert.text"))) {
  153.     win.toggleSidebarWithMetric("flock_AccountsSidebarBroadcaster",
  154.                                 "AccountSidebar-Open",
  155.                                 null,
  156.                                 "PhotoUploaderNoAccounts",
  157.                                 true);
  158.     var inst = this;
  159.     var timerCallback = {
  160.       notify: function timerCallback_notify(aTimer) {
  161.         inst.obs.notifyObservers(null, "toggleAccountsArea", "media");
  162.       }
  163.     };
  164.     var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  165.     timer.initWithCallback(timerCallback, 300, Ci.nsITimer.TYPE_ONE_SHOT);
  166.   }
  167. }
  168.  
  169.  
  170. flockPhotoUploadService.prototype._showUploaderWindow = function PUS__showUploaderWindow () {
  171.   // Set pref that specifies whether the uploader has been used
  172.   var prefService = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService);
  173.   prefService.getBranch("flock.photo.uploader.").setBoolPref("firstruncomplete", true);
  174.   
  175.   var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  176.   var uploaderWindow = wm.getMostRecentWindow("Flock:PhotoUploader");
  177.   var win = wm.getMostRecentWindow('navigator:browser');
  178.   if (uploaderWindow) {
  179.     uploaderWindow.focus();
  180.   } else {
  181.     win.open("chrome://browser/content/flock/photo/photoUploader.xul",
  182.              "PhotoUploader",
  183.              "chrome=1,resizable=1,width=680,height=660");
  184.   }
  185. }
  186.  
  187.  
  188. flockPhotoUploadService.prototype.launchUploader = function PUS_launchUploader () {
  189.   // Tell the user if he has to configure an account
  190.   if (this.hasOnePhotoAccount())
  191.     this._showUploaderWindow();
  192.   else
  193.     this.promptForAccount();
  194. }
  195.  
  196.  
  197. flockPhotoUploadService.prototype.getDefaultService = function() {
  198.   var prefService = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService);
  199.   try {
  200.     var pref = prefService.getBranch("flock.photo.").getCharPref("defaultUploadService");
  201.     if (pref && pref.length)
  202.       return pref;
  203.     return null;
  204.   } catch(e) {
  205.     return null;
  206.   }
  207. }
  208.  
  209. flockPhotoUploadService.prototype.setDefaultService = function(aServiceId) {
  210.   var prefService = Cc['@mozilla.org/preferences-service;1'].getService(Ci.nsIPrefService);
  211.   prefService.getBranch("flock.photo.").setCharPref("defaultUploadService", aServiceId);
  212. }
  213.  
  214.  
  215.  
  216. flockPhotoUploadService.prototype.save = function (aListener) {
  217.   this.Flush();
  218. }
  219.  
  220.  
  221. flockPhotoUploadService.prototype.getURI = function (aURI) {
  222.   return aURI;
  223. }
  224.  
  225. flockPhotoUploadService.prototype.dictionary2Params = function (aDictionary) {
  226.   var params = {};
  227.   var obj = {};
  228.   var count = {};
  229.   var keys = aDictionary.getKeys(count, obj);
  230.   for(var i=0;i<keys.length;++i) {
  231.     var supports = aDictionary.getValue(keys[i]);
  232.     var supportsString = supports.QueryInterface(Ci.nsISupportsString);
  233.     var val = supportsString.toString();
  234.     params[keys[i]] = val;
  235.   }
  236.   return params;
  237. }
  238.  
  239.  
  240. flockPhotoUploadService.prototype.cancelUpload = function () {
  241.   this.uploadListener.stop();
  242. }
  243.  
  244. flockPhotoUploadService.prototype.__defineGetter__('isUploading', function () { return this.running; })
  245. flockPhotoUploadService.prototype.__defineGetter__('isImporting', function () { return this._isImporting; })
  246.  
  247. flockPhotoUploadService.prototype.singleUpload = function(aListener, aAPI, aUpload) {
  248.   var url = this.doTransform(aUpload);
  249.   aAPI.upload(aListener, aUpload, url);
  250.   return;
  251. }
  252.  
  253. flockPhotoUploadService.prototype.addMediaToImportQueue = function (aUrl) {
  254.   this.addToQueue(aUrl);
  255. }
  256.  
  257. flockPhotoUploadService.prototype.importSingleMediaItem = function(aListener, aUrl) {
  258.   this._isImporting = true;
  259.   var inst = this;
  260.   var listener = {
  261.     onCreateStart: function(aTitle) {
  262.       aListener.onMediaImportStart(aTitle, 1);
  263.     },
  264.     
  265.     onCreateEnd: function(aPhotoUpload) {
  266.       inst._isImporting = false;
  267.       aListener.onMediaImportFinish(aPhotoUpload, 1);
  268.     },
  269.     
  270.     onCreateError: function(aFilename) {
  271.       inst._isImporting = false;
  272.       aListener.onMediaImportError(aFilename);
  273.     }
  274.    }
  275.    this.createPhotoUpload(listener, aUrl);
  276.   },
  277.  
  278. flockPhotoUploadService.prototype.addToQueue = function (aUrl) {
  279.   this.mImportQueue.push(aUrl);
  280. }
  281.  
  282. flockPhotoUploadService.prototype.startImportQueue = function (aListener) {
  283.   var inst = this;
  284.   
  285.   var processor = {
  286.     count: 0,
  287.     start: function() {
  288.       for(var i=0;i<inst.listeners.length;++i) {
  289.         inst.listeners[i].onMediaBatchImportStart(inst.mImportQueue.length);
  290.       }
  291.       this.next();
  292.     },
  293.     
  294.     next: function() {
  295.       if (inst.mImportQueue.length == 0) this.finish();
  296.       this.count++;
  297.       var url = inst.mImportQueue.shift();
  298.       try {
  299.         inst.createPhotoUpload(this, url);
  300.       } catch (ex) {
  301.         this.onCreateError(url);
  302.       }
  303.     },
  304.     
  305.     onCreateStart: function(aTitle) {
  306.       for(var i=0;i<inst.listeners.length;++i) {
  307.         inst.listeners[i].onMediaImportStart(aTitle, this.count);
  308.       }  
  309.     },
  310.     
  311.     onCreateEnd: function(aMediaUpload) {
  312.       for(var i=0;i<inst.listeners.length;++i) {
  313.         inst.listeners[i].onMediaImportFinish(aMediaUpload, this.count);
  314.       }
  315.      this.next();      
  316.     },
  317.     
  318.     onCreateError: function(aFilename) {
  319.       for(var i=0;i<inst.listeners.length;++i) {
  320.         inst.listeners[i].onMediaImportError(aFilename);
  321.       }  
  322.     },
  323.  
  324.     onError: function(aError) {
  325.       for(var i=0;i<inst.listeners.length;++i) {
  326.         inst.listeners[i].onError(aError);
  327.       }  
  328.     },
  329.         
  330.     finish: function() {
  331.       inst._isImporting = false;
  332.       for(var i=0;i<inst.listeners.length;++i) {
  333.         inst.listeners[i].onMediaBatchImportFinish();
  334.       }
  335.     }
  336.   }
  337.   
  338.   this._isImporting = true;
  339.   processor.start();
  340. }
  341.  
  342. flockPhotoUploadService.prototype.cancelImport = function () {
  343.   //this.mAsyncCopier.cancel(null);
  344.   this._isImporting = false;
  345.   this.mImportQueue = Array(); // flush the array
  346.   // signal we're done
  347.   for(var i=0;i<this.listeners.length;++i) {
  348.     this.listeners[i].onMediaBatchImportFinish();
  349.   }  
  350. }
  351.  
  352.  
  353. flockPhotoUploadService.prototype.getUniqueFname = function(aFName) {
  354.   aFName.match(/.+\.(.+)/);
  355.   var ext = RegExp.$1;
  356.   if(!ext) ext = "";
  357.   var now = new Date();
  358.   var name = aFName + now + flock_photo.util.callCount++;
  359.   var sinkFileName = FlockCryptoHash.md5(name);
  360.   sinkFileName = sinkFileName + "." + ext;
  361.   return sinkFileName;
  362. }
  363.  
  364. function getOtherFName(aFName, aType) {
  365.   aFName.match(/.+\.(.+)/);
  366.   var ext = RegExp.$1;
  367.   debug(aFName + "." + aType + "." + ext + "\n");
  368.   return aFName + "." + aType + "." + ext;
  369. }
  370.  
  371. flockPhotoUploadService.prototype.cropPhotoUpload = function (aPhotoUpload, aX1, aY1, aX2, aY2) {
  372.   var rotation = parseInt(aPhotoUpload.rotation);
  373.   var cropString = aPhotoUpload.crop;
  374.   var coords = cropString.split(",");
  375.   var x1, y1, x2, y2;
  376.   x1 = parseFloat(coords[0]);
  377.   y1 = parseFloat(coords[1]);
  378.   x2 = parseFloat(coords[2]);
  379.   y2 = parseFloat(coords[3]);
  380.  
  381.   // rotate coords back to coordinate system of the original photo
  382.   function rotateLeftNinetyDegrees() {
  383.     var tmp = aX1;
  384.     aX1 = aY1;
  385.     aY1 = 1 - aX2;
  386.     aX2 = aY2;
  387.     aY2 = 1 - tmp;
  388.   }
  389.  
  390.   var tmp = rotation;
  391.   while(tmp%360!=0) {
  392.     rotateLeftNinetyDegrees();
  393.     tmp -= 90;
  394.   }
  395.  
  396.   var oldW = x2 - x1;
  397.   var oldH = y2 - y1;
  398.  
  399.   aX1 = x1 + oldW * aX1;
  400.   aX2 = x1 + oldW * aX2;
  401.  
  402.   aY1 = y1 + oldH * aY1;
  403.   aY2 = y1 + oldH * aY2;
  404.  
  405.   this.regenerateThumbs(aPhotoUpload, rotation, aX1, aY1, aX2, aY2);
  406. }
  407.  
  408. flockPhotoUploadService.prototype.revertPhotoUpload = function (aPhotoUpload) {
  409.   this.regenerateThumbs(aPhotoUpload,0,0,0,1,1);
  410. }
  411.  
  412. flockPhotoUploadService.prototype.doCrop= function (aPhotoUpload, aDegrees, aSize) {
  413.   var originalPath = aPhotoUpload.originalFilePath;
  414.   var workingPath = aPhotoUpload.workingFilePath;
  415.   var newWorkingFileName = flock_photo.util.getUniqueFname(workingPath);
  416.   var newWorkingFile = flock_getTmpFile(newWorkingFileName);
  417.   var cropString = aPhotoUpload.crop;
  418.  
  419.   var rotation = parseInt(aPhotoUpload.rotation);
  420.   var degrees = rotation;
  421.   var size = null;
  422.  
  423.   if (aDegrees != null) degrees = aDegrees;
  424.   if (aSize != null) size = aSize;
  425.   // do the crop
  426.   if ((cropString == "0,0,1,1") && (aDegrees == 0)) {
  427.     flock_photo.util.resize(size, originalPath, newWorkingFile.path);
  428.   }
  429.   else {
  430.     var coords = cropString.split(",");
  431.     var x1, y1, x2, y2;
  432.     x1 = parseFloat(coords[0]);
  433.     y1 = parseFloat(coords[1]);
  434.     x2 = parseFloat(coords[2]);
  435.     y2 = parseFloat(coords[3]);
  436.  
  437.  
  438.     var origDims = flock_photo.util.getDimensions(originalPath);
  439.  
  440.     var x = Math.floor(x1 * origDims.x);
  441.     var y = Math.floor(y1 * origDims.y);
  442.     var w = Math.ceil((x2 - x1) * origDims.x);
  443.     var h = Math.ceil((y2 - y1) * origDims.y);
  444.     flock_photo.util.cropExt(originalPath,
  445.                       newWorkingFile.path,
  446.                       w,
  447.                       h,
  448.                       x,
  449.                       y,
  450.                       degrees,
  451.                       size,
  452.                       origDims.px,
  453.                       origDims.py
  454.                       );
  455.   }
  456.  
  457.   // create the working file
  458.   return newWorkingFile;
  459. }
  460.  
  461. flockPhotoUploadService.prototype.regenerateThumbs = function (aPhotoUpload, aDegrees, aX1, aY1, aX2, aY2) {
  462.   if(aX1!=null) {
  463.     aPhotoUpload.crop = aX1 + "," + aY1 + "," + aX2 + "," + aY2;
  464.     var newWorkingFile = this.doCrop(aPhotoUpload, 0, FLOCK_PREVIEW_SIZE);
  465.     var newWorkingSpec = flock_photo.util.getURLFromFile(newWorkingFile);
  466.     flock_photo.util.removeFileByPath(aPhotoUpload.workingFilePath);
  467.     aPhotoUpload.workingFilePath = newWorkingFile.path;
  468.     aPhotoUpload.workingFileSpec = newWorkingSpec;
  469.   }
  470.  
  471.   var originalPath = aPhotoUpload.originalFilePath;
  472.   var previewPath = aPhotoUpload.previewFilePath;
  473.   var thumbPath = aPhotoUpload.thumbFilePath;
  474.   var workingPath = aPhotoUpload.workingFilePath;
  475.  
  476.   var rotation = aDegrees;
  477.   var newPreviewFileName = flock_photo.util.getUniqueFname(previewPath);
  478.   var newPreviewFile = flock_getTmpFile(newPreviewFileName);
  479.   flock_photo.util.rotate(rotation, aPhotoUpload.workingFilePath, newPreviewFile.path);
  480.  
  481.   var newPreviewSpec = flock_photo.util.getURLFromFile(newPreviewFile);
  482.  
  483.   var newThumbFileName = flock_photo.util.getUniqueFname(thumbPath);
  484.   var newThumbFile = flock_getTmpFile(newThumbFileName);
  485.   flock_photo.util.thumb(FLOCK_THUMB_SIZE, newPreviewFile.path, newThumbFile.path);
  486.   var newThumbSpec = flock_photo.util.getURLFromFile(newThumbFile);
  487.  
  488.   aPhotoUpload.previewFilePath = newPreviewFile.path;
  489.   aPhotoUpload.previewFileSpec = newPreviewSpec;
  490.  
  491.   aPhotoUpload.thumbFilePath = newThumbFile.path;
  492.   aPhotoUpload.thumbFileSpec = newThumbSpec;
  493.   aPhotoUpload.rotation = rotation + "";
  494.  
  495.   flock_photo.util.removeFileByPath(thumbPath);
  496.   flock_photo.util.removeFileByPath(previewPath);
  497. }
  498.  
  499. flockPhotoUploadService.prototype.rotatePhotoUpload = function (aPhotoUpload, aDegrees) {
  500.   var rotation = (parseInt(aPhotoUpload.rotation) + aDegrees) % 360;
  501.   this.regenerateThumbs(aPhotoUpload, rotation, null, null, null, null);
  502. }
  503.  
  504. flockPhotoUploadService.prototype.createPhotoUpload = function (aListener, aUrl) {
  505.   var url = aUrl;
  506.  
  507.   var sourceFile = flock_getFileFromURL(url);
  508.   var sourceBufferStream = flock_getBufferredInputStream(sourceFile);
  509.   var sourceTitle = sourceFile.leafName;
  510.   var sourceFilename = url;
  511.  
  512.   var sinkFileName = this.getUniqueFname(sourceFilename);
  513.   var sinkFile = flock_getTmpFile(sinkFileName);
  514.   var sinkBufferStream = flock_getBufferredOutputStream(sinkFile);
  515.  
  516.   this.mAsyncCopier.init(sourceBufferStream, sinkBufferStream, null, true, true, FLOCK_IO_CHUNKSIZE);
  517.   aListener.onCreateStart(sourceTitle); 
  518.  
  519.   var inst = this;
  520.  
  521.   var requestObserver = {
  522.     fname: sourceTitle,
  523.     asyncCopier: this.mAsyncCopier,
  524.     url: url,
  525.     sinkFile: sinkFile,
  526.     sinkFileName: sinkFileName,
  527.     preview: false,
  528.     onStartRequest: function(aRequest, aContext) {
  529.     },
  530.     onStopRequest: function(aRequest, aContext) {
  531.       var sourcePath = this.sinkFile.path;
  532.       var thumbPath = getOtherFName(sourcePath, "thumb");
  533.       var previewPath = getOtherFName(sourcePath, "preview");
  534.       var workingPath = getOtherFName(sourcePath, "working");
  535.       flock_photo.util.resizeAsync(FLOCK_PREVIEW_SIZE, sourcePath, previewPath, this);
  536.     },
  537.     onFinished: function requestObserver_onFinished (aResult) {
  538.       debug("onFinished: " + aResult + "\n");
  539.       if (!inst._isImporting) return;
  540.       var sourcePath = this.sinkFile.path;
  541.       var thumbPath = getOtherFName(sourcePath, "thumb");
  542.       var previewPath = getOtherFName(sourcePath, "preview");
  543.       var workingFilePath = getOtherFName(sourcePath, "working");
  544.  
  545.       // if file size is zero
  546.       if (!flock_photo.util.getFileFromPath(sourcePath).fileSize) {
  547.         var error = Components.classes[FLOCK_ERROR_CONTRACTID].createInstance(Ci.flockIError);
  548.         error.errorCode = error.PHOTOSERVICE_FILE_EMPTY;
  549.         aListener.onError(error);
  550.         return;
  551.       }
  552.       
  553.       try {
  554.         if(!this.preview) {
  555.           var previewFile = flock_photo.util.getFileFromPath(previewPath);
  556.           previewFile.copyTo(null, getOtherFName(this.sinkFile.leafName, "working"));
  557.           this.preview = true;
  558.           flock_photo.util.thumbAsync(FLOCK_THUMB_SIZE, previewPath, thumbPath, this);
  559.         } else {
  560.           var thumbFile = flock_photo.util.getFileFromPath(thumbPath);
  561.           var thumbSpec = flock_getURLFromFile(thumbFile);
  562.  
  563.           var previewFile = flock_photo.util.getFileFromPath(previewPath);
  564.           var previewSpec = flock_getURLFromFile(previewFile);
  565.  
  566.           var workingFile = flock_photo.util.getFileFromPath(workingFilePath);
  567.  
  568.           var date = new Date();
  569.           
  570.           var photo = Components.classes['@flock.com/photo-upload;1'].createInstance(Ci.flockIPhotoUpload);
  571.           photo.originalFileSpec = flock_getURLFromFile(this.sinkFile);
  572.           photo.originalFilePath = sourcePath;
  573.           photo.workingFilePath = workingFilePath;
  574.           photo.thumbFileSpec = thumbSpec;
  575.           photo.thumbFilePath = thumbPath;
  576.           photo.previewFileSpec = previewSpec;
  577.           photo.previewFilePath = previewPath;
  578.           photo.privacy_use_batch = "true";
  579.           photo.is_public = "true";
  580.           photo.tags = "";
  581.           photo.notes = "";
  582.           photo.description = "";
  583.           photo.is_friend = "false";
  584.           photo.is_family = "false";
  585.           photo.title = this.fname;
  586.           photo.fileName = this.fname;
  587.           photo.state = "";
  588.           photo.rotation = "0";
  589.           photo.crop = "0,0,1,1";
  590.           photo.id = "uri:" + FlockCryptoHash.md5(sourcePath);
  591.           photo.album = ""; // null for now
  592.           aListener.onCreateEnd(photo);
  593.         }
  594.       } catch (ex) {
  595.         debug("photoupload: " + ex + " in " + ex.fileName+" line "+ex.lineNumber + "\n");
  596.         debug("photoupload: " + ex.description + "\n");
  597.         aListener.onCreateError(this.fname);
  598.       }
  599.     }
  600.   };
  601.  
  602.   this.mAsyncCopier.asyncCopy(requestObserver, requestObserver.sinkFile);
  603. }
  604.  
  605. flockPhotoUploadService.prototype.doTransform = function (aUpload) {
  606.   var url = aUpload.originalFileSpec;
  607.   var path = aUpload.originalFilePath;
  608.  
  609.   // if there are no changes to be made do not create new copy (as it changes jpg compression), just return path
  610.   // see bug 3891
  611.  
  612.   if(flock_getBoolPref(FLOCK_PREF_PHOTO_RESIZE)==true || aUpload.crop!="0,0,1,1" || parseInt(aUpload.rotation)!=0) {
  613.     var maxDim = null;
  614.     if(flock_getBoolPref(FLOCK_PREF_PHOTO_RESIZE)==true) {
  615.       var maxDim = flock_getIntPref(FLOCK_PREF_PHOTO_RESIZE_DIMENSIONS);
  616.     }
  617.     var newFile = this.doCrop(aUpload, null, maxDim);
  618.     url = flock_getURLFromFile(newFile);
  619.  
  620.     flock_photo.util.transferExif(aUpload.originalFileSpec, url);
  621.     return url;
  622.   }
  623.  
  624.   return aUpload.originalFileSpec;
  625. }
  626.  
  627. flockPhotoUploadService.prototype.upload = function (aAPI) {
  628.   if(this.isUploading) { return; }
  629.   var inst = this;
  630.   this.api = aAPI;
  631.   this.uploadListener = {
  632.     init: function(aAPI, aKids, aSvc, aMax) {
  633.       this.api = aAPI;
  634.       this.svc = aSvc;
  635.       this.kids = aKids;
  636.       this.count = 0;
  637.       this.max = aMax;
  638.       this.imageUtils = flock_getImageUtils();
  639.       this.svc.running = true;
  640.       this.doUpload();
  641.     },
  642.     stop: function() {
  643.       this.svc.doSave();
  644.       this.svc.running = false;
  645.       // XXX andy: this isn't in the idl...
  646.       //this.api.cancelUpload();
  647.       for(var i=0;i<this.svc.listeners.length;++i) {
  648.         this.svc.listeners[i].onUploadComplete();
  649.       }
  650.     },
  651.     doUpload: function() {
  652.       if (!this.svc.running || !this.kids.hasMoreElements()) {
  653.         if(this.svc.running) this.stop();
  654.         return;
  655.       }
  656.       ++this.count;
  657.       this.uploadResource = this.kids.getNext();
  658.       var upload = this.svc.getPhotoUpload(this.uploadResource.getTarget(FLOCK_NS + "id").getValue());
  659.       var url = inst.doTransform(upload);
  660.       var params = new Array();
  661.       params.title = upload.title;
  662.       params.description = upload.description;
  663.       params.is_family = upload.is_family;
  664.       params.is_friend = upload.is_friend;
  665.       params.is_public = upload.is_public;
  666.       params.async = "1";
  667.       params.tags = upload.tags;
  668.       params.notes = upload.notes;
  669.       params.album = upload.album;
  670.       this.currentUpload = upload;
  671.       this.uploadResource.addTargetOnce(FLOCK_NS + "state", "uploading");
  672.       for (var i=0;i<this.svc.listeners.length;++i) {
  673.         this.svc.listeners[i].onUploadStart(this.currentUpload, this.count, this.max);
  674.       }
  675.       this.api.upload(this, upload, url);
  676.     },
  677.     onUploadComplete: function(aUpload) {
  678.       this.doUpload();
  679.       for(var i=0;i<this.svc.listeners.length;++i) {
  680.         this.svc.listeners[i].onUpload(aUpload, this.count, this.max);
  681.       }
  682.       this.svc.removePhotoUpload(aUpload, false);
  683.     },
  684.     onUploadFinalized: function(aUpload, aPhoto) {
  685.     },
  686.     onError: function(aError) {
  687.       this.uploadResource.addTargetOnce(FLOCK_NS + "state", "error");
  688.       for(var i=0;i<this.svc.listeners.length;++i) {
  689.         if(this.svc.running) //don't send back error on cancelUpload
  690.           this.svc.listeners[i].onUploadError(this.currentUpload, this.count, this.max, aError);
  691.       }
  692.       this.stop();
  693.       debug("error uploading\n");
  694.     },
  695.     onProgress: function(currentProgress) {
  696.       for(var i=0;i<this.svc.listeners.length;++i) {
  697.         this.svc.listeners[i].onUploadProgress(currentProgress);
  698.       }
  699.     }
  700.   };
  701.   var kids = this.uploadRoot.getChildren();
  702.  
  703.   // XXX have to reverse the order of the child nodes
  704.   // so that the service gets the oldest photo first uploaded.
  705.   var orderedKidsEnumerator  = {
  706.     mList: Array(),
  707.     currentIndex: 0,
  708.     add : function(aItem) {
  709.       this.mList.unshift(aItem);
  710.     },
  711.     getNext : function() {
  712.       this.currentIndex++;
  713.       return this.mList[this.currentIndex-1];
  714.     },
  715.     hasMoreElements : function() {
  716.       return this.mList[this.currentIndex] != null ? true : false;
  717.     },
  718.     getChildCount: function() {
  719.       return this.mList.length;
  720.     }
  721.   }
  722.   while (kids.hasMoreElements())
  723.     orderedKidsEnumerator.add(kids.getNext());
  724.  
  725.   this.uploadListener.init(this.api, orderedKidsEnumerator, this, orderedKidsEnumerator.getChildCount());
  726. }
  727.  
  728. flockPhotoUploadService.prototype.isNewUpload = function (aUpload) {
  729.   if(aUpload.getTarget(FLOCK_NS + "id")) return false;
  730.   return true;
  731. }
  732.  
  733. flockPhotoUploadService.prototype.savePhotoUpload = function (aUpload) {
  734.   debug("flockPhotoUploadService.prototype.savePhotoUpload " + aUpload.id + "\n");
  735.   debug("flockPhotoUploadService.prototype.savePhotoUpload notes = " + aUpload.notes + "\n");
  736.   var upload = this.ds.getNode(this.getURI(aUpload.id));
  737.   upload.addTargetOnce(FLOCK_NS + "id", aUpload.id);
  738.   upload.addTargetOnce(FLOCK_NS + "originalFileSpec", aUpload.originalFileSpec);
  739.   upload.addTargetOnce(FLOCK_NS + "originalFilePath", aUpload.originalFilePath);
  740.   upload.addTargetOnce(FLOCK_NS + "workingFilePath", aUpload.workingFilePath);
  741.   upload.addTargetOnce(FLOCK_NS + "thumbFilePath", aUpload.thumbFilePath);
  742.   upload.addTargetOnce(FLOCK_NS + "thumbFileSpec", aUpload.thumbFileSpec);
  743.   upload.addTargetOnce(FLOCK_NS + "previewFilePath", aUpload.previewFilePath);
  744.   upload.addTargetOnce(FLOCK_NS + "previewFileSpec", aUpload.previewFileSpec);
  745.   upload.addTargetOnce(FLOCK_NS + "fileName", aUpload.fileName);
  746.   upload.addTargetOnce(FLOCK_NS + "title", aUpload.title);
  747.   upload.addTargetOnce(FLOCK_NS + "privacy_use_batch", aUpload.privacy_use_batch);
  748.   upload.addTargetOnce(FLOCK_NS + "is_public", aUpload.is_public);
  749.   upload.addTargetOnce(FLOCK_NS + "is_friend", aUpload.is_friend);
  750.   upload.addTargetOnce(FLOCK_NS + "is_family", aUpload.is_family);
  751.   upload.addTargetOnce(FLOCK_NS + "tags", aUpload.tags);
  752.   upload.addTargetOnce(FLOCK_NS + "notes", aUpload.notes);
  753.   upload.addTargetOnce(FLOCK_NS + "state", aUpload.state);
  754.   upload.addTargetOnce(FLOCK_NS + "description", aUpload.description);
  755.   upload.addTargetOnce(FLOCK_NS + "rotation", aUpload.rotation);
  756.   upload.addTargetOnce(FLOCK_NS + "album", aUpload.album);
  757.   upload.addTargetOnce(FLOCK_NS + "crop", aUpload.crop);
  758.   this.doSave();
  759. }
  760.  
  761. flockPhotoUploadService.prototype.addPhotoUpload = function (aReference, aUpload) {
  762.   debug("flockPhotoUploadService.prototype.addPhotoUpload " + aUpload.state + "\n");
  763.   for(var i=0;i<this.listeners.length;++i) {
  764.     this.listeners[i].onUploadAdd(null);
  765.   }
  766.  
  767.   var newUpload = this.ds.getNode(this.getURI(aUpload.id));
  768.   this.uploadRoot.removeChildForReal(newUpload);
  769.  
  770.   if(this.isNewUpload(newUpload)) {
  771.     this.savePhotoUpload(aUpload);
  772.   }
  773.   if(aReference) {
  774.     var ref = this.ds.getNode(this.getURI(aReference.id));
  775.     var index = this.uploadRoot.getChildIndex(ref);
  776.     this.uploadRoot.addChildAt(newUpload, index);
  777.   }
  778.   else {
  779.     this.uploadRoot.addChildAt(newUpload, 1);
  780.   }
  781.   this.doSave();
  782.   for(var i=0;i<this.listeners.length;++i) {
  783.     this.listeners[i].onUploadAdd(aUpload);
  784.   }
  785. }
  786.  
  787.  
  788. flockPhotoUploadService.prototype.removePhotoUpload = function (aUpload, aDontDelete) {
  789.   try {
  790.     aUpload = this.getPhotoUpload(aUpload.id);
  791.   }
  792.   catch(e) {}
  793.   var toDelete = this.ds.getNode(this.getURI(aUpload.id));
  794.   this.uploadRoot.removeChild(toDelete);
  795.   this.ds.deleteRecursive(toDelete);
  796.   this.doSave();
  797.   if(!aDontDelete) {
  798.     try {
  799.     flock_photo.util.removeFileByPath(aUpload.workingFilePath);
  800.     flock_photo.util.removeFileByPath(aUpload.originalFilePath + "_backup");
  801.     flock_photo.util.removeFileBySpec(aUpload.originalFileSpec);
  802.     flock_photo.util.removeFileBySpec(aUpload.previewFileSpec);
  803.     flock_photo.util.removeFileBySpec(aUpload.thumbFileSpec);
  804.     flock_photo.util.removeFileByPath(aUpload.originalFilePath);
  805.     flock_photo.util.removeFileByPath(aUpload.previewFilePath);
  806.     flock_photo.util.removeFileByPath(aUpload.thumbFilePath);
  807.     } catch(e) {
  808.     }
  809.   }
  810.   for(var i=0;i<this.listeners.length;++i) {
  811.     this.listeners[i].onUploadRemove();
  812.   }
  813. }
  814.  
  815. flockPhotoUploadService.prototype.reorderPhotoUpload = function (aReference, aUpload) {
  816.   this.addPhotoUpload();
  817.   return;
  818. }
  819.  
  820. flockPhotoUploadService.prototype.getPhotoUpload = function (aURI) {
  821.   var upload = this.ds.getNode(this.getURI(aURI));
  822.   var rval = new Object();
  823.   rval.id = upload.getTarget(FLOCK_NS + "id").getValue();
  824.   rval.originalFileSpec = upload.getTarget(FLOCK_NS + "originalFileSpec").getValue();
  825.   rval.originalFilePath = upload.getTarget(FLOCK_NS + "originalFilePath").getValue();
  826.   rval.workingFilePath = upload.getTarget(FLOCK_NS + "workingFilePath").getValue();
  827.   rval.thumbFileSpec = upload.getTarget(FLOCK_NS + "thumbFileSpec").getValue();
  828.   rval.thumbFilePath = upload.getTarget(FLOCK_NS + "thumbFilePath").getValue();
  829.   rval.previewFileSpec = upload.getTarget(FLOCK_NS + "previewFileSpec").getValue();
  830.   rval.previewFilePath = upload.getTarget(FLOCK_NS + "previewFilePath").getValue();
  831.   rval.fileName = upload.getTarget(FLOCK_NS + "fileName").getValue();
  832.   rval.title = upload.getTarget(FLOCK_NS + "title").getValue();
  833.   rval.privacy_use_batch = upload.getTarget(FLOCK_NS + "privacy_use_batch").getValue();
  834.   rval.is_public = upload.getTarget(FLOCK_NS + "is_public").getValue();
  835.   rval.is_friend = upload.getTarget(FLOCK_NS + "is_friend").getValue();
  836.   rval.is_family = upload.getTarget(FLOCK_NS + "is_family").getValue();
  837.   rval.tags = upload.getTarget(FLOCK_NS + "tags").getValue();
  838.   rval.notes = upload.getTarget(FLOCK_NS + "notes").getValue();
  839.   rval.state = upload.getTarget(FLOCK_NS + "state").getValue();
  840.   rval.description = upload.getTarget(FLOCK_NS + "description").getValue();
  841.   rval.rotation = upload.getTarget(FLOCK_NS + "rotation").getValue();
  842.   rval.album = upload.getTarget(FLOCK_NS + "album").getValue();
  843.   rval.crop = upload.getTarget(FLOCK_NS + "crop").getValue();
  844.   return rval;
  845. }
  846.  
  847. flockPhotoUploadService.prototype.cleanPhotoUploadCache = function () {
  848.   debug("Clean the cache.\n");
  849.   try {
  850.     var sinkFile = Cc["@mozilla.org/file/directory_service;1"]
  851.       .getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile);
  852.     sinkFile.append("flock_imagecache");
  853.     if (sinkFile.exists()) {
  854.       debug("Image cache found\n");
  855.       var files = sinkFile.directoryEntries;
  856.       while (files.hasMoreElements()) {
  857.         var file = files.getNext().QueryInterface(Ci.nsIFile);
  858.         try {
  859.           file.remove(false);
  860.         } catch (e) {
  861.           debug("could not delete file: " + file.path + " exception: " + e + "\n");
  862.         }
  863.       }
  864.     } else {
  865.       debug("Image cache not found\n");
  866.     }
  867.   } catch (e) {
  868.     debug("exception cleaning the cache: " + e + "\n");
  869.   }
  870. }
  871.  
  872. // nsIObserver
  873. flockPhotoUploadService.prototype.observe =
  874. function PUS_observe (subject, topic, state)
  875. {
  876.   switch (topic) {
  877.     case 'flock-data-ready':
  878.       this.obs.removeObserver(this, 'flock-data-ready');
  879.       this.init();
  880.       return;
  881.   }
  882. }
  883.  
  884. loadLibraryFromSpec("chrome://flock/content/common/flocksafe.js");
  885. loadLibraryFromSpec('chrome://browser/content/flock/contrib/rdfds.js');
  886. loadLibraryFromSpec('chrome://browser/content/flock/photo/photoAPI.js');
  887. loadLibraryFromSpec('chrome://browser/content/flock/photo/photo.js');
  888.  
  889. function loadLibraryFromSpec(aSpec) {
  890.   var loader = Cc['@mozilla.org/moz/jssubscript-loader;1'].getService(Ci.mozIJSSubScriptLoader);
  891.  
  892.   loader.loadSubScript(aSpec);
  893. }
  894.  
  895. flockPhotoUploadService.prototype.URI = 'rdf:flock-photo-uploads';
  896. flockPhotoUploadService.prototype.GetSource = function (aProperty, aTarget, aTruthValue) {
  897.   return this.dataSource.GetSource (aProperty, aTarget, aTruthValue);
  898. }
  899. flockPhotoUploadService.prototype.GetSources = function (aProperty, aTarget, aTruthValue) {
  900.   return this.dataSource.GetSources (aProperty, aTarget, aTruthValue);
  901. }
  902. flockPhotoUploadService.prototype.GetTarget = function (aSource, aProperty, aTruthValue) {
  903.   return this.dataSource.GetTarget (aSource, aProperty, aTruthValue);
  904. }
  905. flockPhotoUploadService.prototype.GetTargets = function (aSource, aProperty, aTruthValue) {
  906.   return this.dataSource.GetTargets (aSource, aProperty, aTruthValue);
  907. }
  908. flockPhotoUploadService.prototype.Assert = function (aSource, aProperty, aTarget, aTruthValue) {
  909.   this.dataSource.Assert (aSource, aProperty, aTarget, aTruthValue);
  910. }
  911. flockPhotoUploadService.prototype.Unassert = function (aSource, aProperty, aTarget) {
  912.   this.dataSource.Unassert (aSource, aProperty, aTarget);
  913. }
  914. flockPhotoUploadService.prototype.Change = function (aSource, aProperty, aOldTarget, aNewTarget) {
  915.   this.dataSource.Change (aSource, aProperty, aOldTarget, aNewTarget);
  916. }
  917. flockPhotoUploadService.prototype.Move = function (aOldSource, aNewSource, aProperty, aTarget) {
  918.   this.dataSource.Move (aOldSource, aNewSource, aProperty, aTarget);
  919. }
  920. flockPhotoUploadService.prototype.HasAssertion = function (aSource, aProperty, aTarget, aTruthValue) {
  921.   return this.dataSource.HasAssertion (aSource, aProperty, aTarget, aTruthValue);
  922. }
  923. flockPhotoUploadService.prototype.AddObserver = function (aObserver) {
  924.   this.dataSource.AddObserver (aObserver);
  925. }
  926. flockPhotoUploadService.prototype.RemoveObserver = function (aObserver) {
  927.   this.dataSource.RemoveObserver (aObserver);
  928. }
  929. flockPhotoUploadService.prototype.ArcLabelsIn = function (aNode) {
  930.   return this.dataSource.ArcLabelsIn (aNode);
  931. }
  932. flockPhotoUploadService.prototype.ArcLabelsOut = function (aNode) {
  933.   return this.dataSource.ArcLabelsOut (aNode);
  934. }
  935. flockPhotoUploadService.prototype.GetAllResources = function () {
  936.   return this.dataSource.GetAllResources ();
  937. }
  938. flockPhotoUploadService.prototype.IsCommandEnabled = function (aSources, aCommand, aArguments) {
  939.   return this.dataSource.IsCommandEnabled (aSources, aCommand, aArguments);
  940. }
  941. flockPhotoUploadService.prototype.DoCommand = function (aSources, aCommand, aArguments) {
  942.   this.dataSource.DoCommand (aSources, aCommand, aArguments);
  943. }
  944. flockPhotoUploadService.prototype.GetAllCmds = function (aSource) {
  945.   return this.dataSource.GetAllCmds (aSource);
  946. }
  947. flockPhotoUploadService.prototype.hasArcIn = function (aNode, aArc) {
  948.   return this.dataSource.hasArcIn (aNode, aArc);
  949. }
  950. flockPhotoUploadService.prototype.hasArcOut = function (aNode, aArc) {
  951.   return this.dataSource.hasArcOut (aNode, aArc);
  952. }
  953. flockPhotoUploadService.prototype.beginUpdateBatch = function () {
  954.   this.dataSource.beginUpdateBatch ();
  955. }
  956. flockPhotoUploadService.prototype.endUpdateBatch = function () {
  957.   this.dataSource.endUpdateBatch ();
  958. }
  959. flockPhotoUploadService.prototype.Flush = function () {
  960.   this.dataSource.Flush ();
  961. }
  962. flockPhotoUploadService.prototype.FlushTo = function (aURI) {
  963.   this.dataSource.FlushTo (aURI);
  964. }
  965. flockPhotoUploadService.prototype.Init = function (aURI) {
  966.   this.dataSource.Init (aURI);
  967. }
  968. flockPhotoUploadService.prototype.Refresh = function (aBlocking) {
  969.   this.dataSource.Refresh (aBlocking);
  970. }
  971.  
  972. flockPhotoUploadService.prototype.flags = Ci.nsIClassInfo.SINGLETON;
  973. flockPhotoUploadService.prototype.classDescription = "Flock Photo Service";
  974. flockPhotoUploadService.prototype.getInterfaces = function (count) {
  975.   var interfaceList = [Ci.flockIPhotoUploadService, Ci.nsIClassInfo, Ci.nsIObserver];
  976.   count.value = interfaceList.length;
  977.   return interfaceList;
  978. }
  979. flockPhotoUploadService.prototype.getHelperForLanguage = function (count) {return null;}
  980.  
  981. // the nsISupports implementation
  982. flockPhotoUploadService.prototype.QueryInterface =
  983. function (iid) {
  984.   if (!iid.equals(Ci.flockIPhotoUploadService) &&
  985.     !iid.equals(Ci.nsIRDFDataSource) &&
  986.     !iid.equals(Ci.nsIClassInfo) &&
  987.     !iid.equals(Ci.nsIObserver) &&
  988.     !iid.equals(Ci.nsISupports))
  989.     throw Cr.NS_ERROR_NO_INTERFACE;
  990.   if (iid.equals(Ci.nsIRDFDataSource) && !this.dataSourceSetup) {
  991.   }
  992.   return this;
  993. }
  994.  
  995. // Module implementation
  996. var Module = new Object();
  997.  
  998. Module.registerSelf =
  999. function (compMgr, fileSpec, location, type)
  1000. {
  1001.   compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  1002.  
  1003.   compMgr.registerFactoryLocation(FLOCK_PHOTO_UPLOAD_CID,
  1004.                                   "Flock Photo JS Component",
  1005.                                   FLOCK_PHOTO_UPLOADS_CONTRACTID,
  1006.                                   fileSpec,
  1007.                                   location,
  1008.                                   type);
  1009.   var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  1010.   categoryManager.addCategoryEntry("flock-startup", "Flock Photo Upload Service", "service," + FLOCK_PHOTO_UPLOADS_CONTRACTID, true, true);
  1011. }
  1012.  
  1013. Module.getClassObject =
  1014. function (compMgr, cid, iid) {
  1015.   if (!cid.equals(FLOCK_PHOTO_UPLOAD_CID))
  1016.     throw Cr.NS_ERROR_NO_INTERFACE;
  1017.  
  1018.   if (!iid.equals(Ci.nsIFactory))
  1019.     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  1020.  
  1021.   return PhotoUploadServiceFactory;
  1022. }
  1023.  
  1024. Module.canUnload =
  1025. function(compMgr) {
  1026.   return true;
  1027. }
  1028.  
  1029. /* factory object */
  1030. var PhotoUploadServiceFactory = new Object();
  1031.  
  1032. PhotoUploadServiceFactory.createInstance =
  1033. function (outer, iid) {
  1034.   if (outer != null)
  1035.     throw Components.results.NS_ERROR_NO_AGGREGATION;
  1036.  
  1037.   return (new flockPhotoUploadService()).QueryInterface(iid);
  1038. }
  1039.  
  1040. /* entrypoint */
  1041. function NSGetModule(compMgr, fileSpec) {
  1042.   return Module;
  1043. }
  1044.